<?php
/**
	classes:
		server
		server :: sitePointer (extends node)
		server :: sitePointer :: site

		database
*/


// class for site definition. Site acts as a container fo the general sites variables: directories and domain.
class site {
	public $domain;
	public $subdomain;
	public $path='includes/sites/'; // Sites folder path
	public $style="stylesheets/main.css";	// Site shtylesheet file path
	public $js="javascript/"; // javascript folder
	public $folder; // Folder of the site
	public $href; //href of the site

	// Loading the site configuration constants for the database
	function load_db_config(){
		//We load the site configuration db
		$filename=$this->path.$this->folder.'config.php';
		if (is_file($filename)) {
			include($filename);
		}
	}
	// Loading the site configuration constants for domains
	function load_domain_config(){
		$parseStr=null;
		//We load the site configuration domain
		$filename=$this->path.$this->folder.'config.inc';
		if (is_file($filename)) {
			$parseStr=file_get_contents($filename);
		}
		return $parseStr;
	}
	/*
	 * It checks if the $host match the host names of the site.
	 * The word * at the subdomain indicates that this site works to any subdomain
	 */
	function is_host($host) {
			switch ($this->subdomain) {
				case '*':
					$match_string=$this->domain;
					break;
				default :
					$match_string=$this->subdomain . '.' . $this->domain;
			}
		if (preg_match('/'.$match_string.'/', $host)) return true;
		else return false;
	}
	//Stablish the site variables with the sites configuration constants
	function set_data($domain,$subdomain) {
		$this->domain=$domain;
		$this->subdomain=$subdomain;
		if ($this->subdomain != '*') $this->href=$this->subdomain . '.' . $this->domain;
		else $this->href=$this->domain;
	}
}
//This is equivalent to node class but for sites node tree managing. It includes the site pointer as its information container variable.
class sitePointer extends node {
	public $site; //This is a pointer to the site object form the node.

	//equivalent to the parent node function but for sitePointers
	function unserialize($nodesTxt) {
		//$nodesTxt is an array of string node names splitted by the string delimiter "::"
		$stringDelimiter="::";
		foreach ($nodesTxt as $nodeTxt) {
			$nodePointer=$this;	//We point to the node. $this is a void node, acts only as a pointer to the node tree
			$nodeNamesPath=explode($stringDelimiter,$nodeTxt);
			foreach ($nodeNamesPath as $nodeName) {
				$index=$nodePointer->has_children($nodeName);
				if ($index >-1) {
					//we are navegating through a branch
					$nodePointer=$nodePointer->children[$index];
				}
				else {
					//New node because there is no such a node in the branch, we add it to the branch end
					$newNode=new sitePointer();
					$newNode->name=$nodeName;
					$newNode->parentNode=$nodePointer;
					array_push($nodePointer->children, $newNode);
					$nodePointer=$newNode;	//$nodePointer points now to the last node added. If there are more iterations more nodes will be added
				}
			}
		}
	}
	//It loads the site information from all of the tree nodes
	function load_sites() {
		$nodePointer=$this; // Node pointer points at the index node.
		$copyPointer=unserialize(serialize($this));	//we create a copy for managing the node tree to manipulate without restrictions (look method remove_child)
		$startPointer=$copyPointer; // A pointer to the copy index
		$index=0;
		while (count($copyPointer->children) > 0) {
			while (count($copyPointer->children) > 0) {
				//we get to the last node of the branch
				$copyPointer=$copyPointer->children[0];
				$nodePointer=$nodePointer->children[0]; //we follow a parallel travel with the actual node tree pointer
			}
			$copyPointer->parentNode->remove_children(0);
			// We have to calculate what is the node index number for the original nodePointer and that is the total removed children less 1
			$nodeIndex=count($nodePointer->parentNode->children) - count($copyPointer->parentNode->children) -1;
			$nodePointer->parentNode->children[$nodeIndex]->load_site(); //We load the site object data
			$copyPointer=$startPointer; //we startby the beginning
			$nodePointer=$this; //the same for our actual node tree pointer
		}
	}
	//It load the site object and information for the actual site
	function load_site() {
		$this->site=new site();
		$this->site->folder=$this->name.'/';
		// Once we get the site folder we can load the site constants
		$parseStr=$this->site->load_domain_config(); //It loads the site constants
		parse_str($parseStr);
		$this->site->set_data($domain,$subdomain); //It sets the constants to the site
	}
	//It gets the site path name from the $host_name that is subdomain and domain
	function get_site_path($host_name){
		$stringDelimiter="::";
		$nodePointer=unserialize(serialize($this)); //we get a copy to work on it
		$nodeStart=$nodePointer;
		while (count($nodePointer->children) > 0) {
			$value=array();
			while (count($nodePointer->children) > 0) {
				$nodePointer=$nodePointer->children[0];
				array_push($value,$nodePointer->name);
				//we have created the list with the sites names to the end node
			}
			if ($nodePointer->site->is_host($host_name)) {
				//If there is coincidence to the $host_name we have found the siteNode and we can return the node list that is the path to the node
				return implode($stringDelimiter,$value);
			}
			else {
				// We haven't found it yet so we discard the end node to start the searching from the beginning
				$nodePointer->parentNode->remove_children(0); // $nodePointer siteNode is erased and nodePointer is null
				$nodePointer=$nodeStart; // We restart the search
			}
		}
		return false; //If there is no coincidence returns false
	}
}

/*
 * This object puropse is to manage site objects.
 */
class server {
	public $sites;	//This is referring to all the sites hosted in the server. A pointer to the nodes, actually is an array to the root nodes.
	public $my_site=array();	//This is referring to the actual site and his parents in a sites array
	public $db_data;
	public $db;

	function init() {
		$this->my_site[0]->load_db_config(); //We load the actual site database access data and some other information
		// define our database connection
		$this->db = new database;
		$this->db->set(
			array(
				"server"		=> DB_SERVER,
				"name"		=> DB_NAME,
				"user_name"	=> DB_USER_NAME,
				"user_pwd"	=> DB_USER_PWD
			)
		);
		/* check connection */
		if ($this->db->my_connect()) {
		    printf("Connect failed: %s\n", mysqli_connect_error());
		    exit();
		}
	}
	/*
	 * It loads the sitesNodes from the sites list at the general configuration file
	 */
	function load_sites() {
		$sitePathDelimiter=";";
		$sitePointer=new sitePointer(); //A void pointer to point to the sites tree. It is allways the start pointer.
		$sitePointer->unserialize(explode($sitePathDelimiter, SITES_STRUCTURE));
		$sitePointer->load_sites(); //It loads the sites configuration constants into the sites at the node site variable.
		$this->sites=$sitePointer;
	}
	/*
	 * It orginize the sites array in a way that $host will be the first one, and the following ones
	 * will be the parent ones of it.
	 * In case that no site domain name match $host it will create the list from the first site of the array
	 */
	function set_default($host) {
		$this->my_site=array();
		$sitePath=$this->sites->get_site_path($host);
		if ($sitePath)	{
			$nodePointer=$this->sites->get_node_from_path($sitePath); // $nodePointer points to the siteNode we are searching for
			$nodeParents=$nodePointer->get_parents(); // We get an array of the node parents of $nodePointer
			array_pop($nodeParents); // We remove the first array element that is just the pointer to the sites
			array_push($nodeParents,$nodePointer); // We add $nodePointer to the list to complet the sites of interest
			// The list shold be reverser to search first at the actual site and then to its parents
			foreach ($nodeParents as $node) {
				array_push($this->my_site, $node->site);
			}
		}
		else {
			$this->my_site[0]=$this->sites->children[0]->site; // When the $host is not at the sites we just choose the first site at the list
		}
	}
	/*
	 * This function consists in the way of recovering the site's files. If a site file is not found it will tray to get the file at the parents sites.
	 */
	 function get_path_name($filename) {
		foreach ($this->my_site as $site) {
			$filepath=$site->path.$site->folder.$filename;
			if (is_file($filepath)) {
				return($filepath);
			}
		}
		return false;
	 }
	 //To detect bots that doesn't use javascript and then to send them an compatible version of the page
	function bot_detect($user_agent) {
		if (preg_match('/bot|crawl|slurp|spider/i', $user_agent)) {
			return true;
		}
		else {
			return false;
		}
	}
}

class database {
	// Database configuration variables
	public $server;
	public $user_name;
	public $user_pwd;
	public $name;
	//database link
	public $link;

	//Database user data set
	function set($row) {
		$this->server=$row["server"];
		$this->user_name=$row["user_name"];
		$this->user_pwd=$row["user_pwd"];
		$this->name=$row["name"];
	}
	#Database connection
	function my_connect() {
		$this->link = new mysqli($this->server, $this->user_name, $this->user_pwd, $this->name);
		$this->link->set_charset("utf8");
		$this->link->query("SET character_set_results='utf8'");
		return mysqli_connect_errno();
	}
}
?>
